package com.silky.officeline.thread;


import com.silky.common.bean.DataSourceConfig;
import com.silky.common.bean.MultiLevelJoinConfig;
import com.silky.common.bean.NodeConfig;
import com.silky.common.service.NodeService;
import com.silky.common.utils.ThreadSafeList;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
 * 多级关联更新线程(含更新，插入及删除)
 */
public class MultiLevelUpdateThread extends AbstractThread {


    private final DataSourceConfig dataSourceConfig;
    private final MultiLevelJoinConfig multiLevelJoinConfig;
    private final ThreadSafeList parentNodeDatas;
    private final NodeConfig currentNode;
    private final int currentLevel;
    private final CountDownLatch currentCountDownLatch;
    private NodeService nodeService;
    public MultiLevelUpdateThread(DataSourceConfig dataSourceConfig,
                                  MultiLevelJoinConfig multiLevelJoinConfig,
                                  ThreadSafeList parentNodeDatas,
                                  NodeConfig currentNode, int currentLevel, CountDownLatch currentCountDownLatch) {
        //数据源配置
        this.dataSourceConfig = dataSourceConfig;
        //节点配置
        this.multiLevelJoinConfig = multiLevelJoinConfig;
        //父级数据源
        this.parentNodeDatas = parentNodeDatas;
        //当前节点
        this.currentNode = currentNode;
        //当前层级
        this.currentLevel = currentLevel;
        nodeService = new NodeService(dataSourceConfig);
        this.currentCountDownLatch = currentCountDownLatch;
    }

    @Override
    public void run()
    {
        System.out.println("MultiLevelUpdateThread当前线程："+Thread.currentThread().getName()+"开始启动");
        //获取更新语句的数据集别名列表
        List<String> dataSetNames = nodeService.getUpdateSqlDataSetNames(currentNode.getUpdateSql());
        //别名列表必须等于1或者0,否则报错
        if(!(dataSetNames.size() == 1 || dataSetNames.size() == 0))
        {
            System.out.println("MultiLevelUpdateThread当前线程："+Thread.currentThread().getName()+"退出");
            throw new RuntimeException("更新语句必须包含一个数据集获取为空");
        }
        //如果别名列表等于1，则替换sql模板中的${xxx}为数据集
        String dataSetName = dataSetNames.get(0);
        Connection conn = null;
        try {
            long size = parentNodeDatas.size();
            System.out.println("parentNodeDatas size:"+parentNodeDatas.size());
            if(size == 0) {
                System.out.println("MultiLevelUpdateThread当前线程："+Thread.currentThread().getName()+"退出");
                return;
            }
            conn = nodeService.getConnectionByDataSourceName(currentNode.getDataSourceName());

            //循环数据集
            while(true) {
                //Map<String, Object> parentNodeData = parentNodeDatas.remove();
                List<Map<String, Object>> parentNodeDataList = parentNodeDatas.removeByNum(100);
                if (parentNodeDataList != null && !parentNodeDataList.isEmpty()) {
                    for(int i=0;i<parentNodeDataList.size();i++) {
                        currentCountDownLatch.countDown();
                    }
                    //生成复合map
                    List<Map<String,Object>> compositeMaps = new ArrayList<>();
                    for(int i=0;i<parentNodeDataList.size();i++) {
                        if(traceLostData(parentNodeDataList.get(i))){
                            System.out.println("遗漏数据:"+parentNodeDataList.get(i));
                        }
                        compositeMaps.add(makeCompositeMap(parentNodeDataList.get(i), dataSetName));
                    }
                    //执行更新语句
                    nodeService.getSqlService().doBatchUpdate(conn, currentNode.getUpdateSql(), compositeMaps);
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(conn != null){
                nodeService.closeConnection(conn);
            }
        }
        System.out.println("MultiLevelUpdateThread当前线程："+Thread.currentThread().getName()+"退出");
    }

    /**
     *
     * @param parentNodeData
     * @param dataSetName
     * @return
     */
    private Map<String, Object> makeCompositeMap(Map<String, Object> parentNodeData, String dataSetName) {
        Map<String,Object> retMap = new HashMap<>();
        for(String key: parentNodeData.keySet()){
            retMap.put("${"+dataSetName+"."+key+"}",parentNodeData.get(key));
        }
        return retMap;
    }
    private boolean traceLostData(Map<String, Object> currentNodeData) {
        String schemeId = currentNodeData.get("schemeId").toString();
        if(schemeId.equals("2479355402210705408")){
            return true;
        }

        return false;
    }
}
